package top.v5it.japi.plus.spring.boot.autoconfigure;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import top.v5it.japi.plus.core.cache.JapiCache;
import top.v5it.japi.plus.core.spring.web.interceptor.*;
import top.v5it.japi.plus.log.OperLogService;
import top.v5it.japi.plus.spring.boot.autoconfigure.properties.JapiProperties;

import java.util.HashMap;
import java.util.Map;

/**
 * 自动装配当前应用程序所需要的拦截器
 *
 * @author zhanpu
 * @date 2020-11-24
 */
@Slf4j
@ConfigurationProperties("spring.japi.interceptor")
public class JapiInterceptorConfiguration {

    private static final String SPRING_JAPI_INTERCEPTOR_AUTHORIZED_TYPE = "spring.japi.interceptor.authorized.type";
    private static final String SPRING_JAPI_INTERCEPTOR_EADA = "spring.japi.interceptor.eada";
    private static final String SPRING_JAPI_INTERCEPTOR_EADA_ALGORITHM = "spring.japi.interceptor.eada.algorithm";
    private static final String SPRING_JAPI_INTERCEPTOR_TOKEN = "spring.japi.interceptor.token";

    /**
     * 配置HmacAuthorized
     */
    @ConditionalOnProperty(name = SPRING_JAPI_INTERCEPTOR_AUTHORIZED_TYPE, havingValue = "HMAC_SHA256")
    static class HmacAuthorized {

        /**
         * 为当前应用程序注入授权验证拦截器
         *
         * @param japiCache      {@link JapiCache}
         * @param operLogService {@link OperLogService}
         * @return {@link JapiAuthorizedInterceptor}
         */
        @Bean
        @ConditionalOnMissingBean
        public JapiAuthorizedInterceptor japiHmacSignatureAuthorizedInterceptor(JapiCache japiCache, OperLogService operLogService, JapiProperties japiProperties) {
            log.info(">>>>>>>>>>[Init JapiHmacSignatureAuthorizedInterceptor]<<<<<<<<<<");
            JapiProperties.Interceptor.Authorized authorized = japiProperties.getInterceptor().getAuthorized();
            return new JapiHmacSignatureAuthorizedInterceptor(japiCache, operLogService, authorized.getTimeout(), authorized.getDiffTime());
        }

        /**
         * 为当前应用程序注入响应结果包装器
         *
         * @return {@link JapiResponseWrapper}
         */
        @Bean
        @ConditionalOnMissingBean
        public JapiResponseWrapper japiResponseWrapper() {
            log.info(">>>>>>>>>>[Init JapiHmacSignatureResponseWrapper]<<<<<<<<<<");
            return new JapiHmacSignatureResponseWrapper();
        }
    }

    /**
     * 配置ShaAuthorized
     */
    @ConditionalOnProperty(name = SPRING_JAPI_INTERCEPTOR_AUTHORIZED_TYPE, havingValue = "SHA256_RSA2048")
    static class ShaAuthorized {

        /**
         * 为当前应用程序注入授权验证拦截器
         *
         * @param japiCache      {@link JapiCache}
         * @param operLogService {@link OperLogService}
         * @return {@link JapiAuthorizedInterceptor}
         */
        @Bean
        @ConditionalOnMissingBean
        public JapiAuthorizedInterceptor japiSha256SignatureAuthorizedInterceptor(JapiCache japiCache, OperLogService operLogService, JapiProperties japiProperties) {
            log.info(">>>>>>>>>>[Init JapiSha256SignatureAuthorizedInterceptor]<<<<<<<<<<");
            JapiProperties.Interceptor.Authorized authorized = japiProperties.getInterceptor().getAuthorized();
            return new JapiSha256SignatureAuthorizedInterceptor(japiCache, operLogService, authorized.getTimeout(), authorized.getDiffTime());
        }


        /**
         * 为当前应用程序注入响应结果包装器
         *
         * @return {@link JapiResponseWrapper}
         */
        @Bean
        @ConditionalOnMissingBean
        public JapiResponseWrapper japiResponseWrapper() {
            log.info(">>>>>>>>>>[Init JapiSha256SignatureResponseWrapper]<<<<<<<<<<");
            return new JapiSha256SignatureResponseWrapper();
        }
    }

    /**
     * 为当前应用程序注入加解密拦截器
     *
     * @return {@link JapiEadaInterceptor}
     */
    @Bean
    @ConfigurationProperties(SPRING_JAPI_INTERCEPTOR_EADA)
    @ConditionalOnProperty(SPRING_JAPI_INTERCEPTOR_EADA_ALGORITHM)
    @ConditionalOnMissingBean
    public JapiEadaInterceptor japiEadaInterceptor() {
        log.info(">>>>>>>>>>[Init JapiEadaInterceptor]<<<<<<<<<<");
        return new JapiEadaInterceptor();
    }

    /**
     * 为当前应用程序注入免token检验拦截器
     *
     * @param japiCache      {@link JapiCache}
     * @param operLogService {@link OperLogService}
     * @return {@link JapiTokenInterceptor}
     */
    @Bean
    @ConditionalOnProperty(prefix = SPRING_JAPI_INTERCEPTOR_TOKEN, name = "enabled")
    @ConditionalOnMissingBean
    public JapiTokenInterceptor japiTokenInterceptor(JapiCache japiCache, OperLogService operLogService) {
        log.info(">>>>>>>>>>[Init JapiTokenInterceptor]<<<<<<<<<<");
        return new JapiTokenInterceptor(japiCache, operLogService);
    }

    /**
     * 为当前应用程序注入拦截器
     *
     * @param japiAuthorizedInterceptor {@link JapiAuthorizedInterceptor}
     * @param japiEadaInterceptor       {@link JapiEadaInterceptor}
     * @param japiTokenInterceptor      {@link JapiTokenInterceptor}
     * @return {@link Map<Integer, HandlerInterceptor>}
     */
    @Bean
    @ConditionalOnBean(HandlerInterceptor.class)
    public Map<Integer, HandlerInterceptor> handlerInterceptors(@Nullable JapiAuthorizedInterceptor japiAuthorizedInterceptor,
                                                                @Nullable JapiEadaInterceptor japiEadaInterceptor,
                                                                @Nullable JapiTokenInterceptor japiTokenInterceptor) {
        log.info(">>>>>>>>>>[Init Map<Integer, HandlerInterceptor>]<<<<<<<<<<");
        return new HashMap<Integer, HandlerInterceptor>() {
            private static final long serialVersionUID = 4814707846678866096L;

            {
                put(10, japiAuthorizedInterceptor);
                put(20, japiEadaInterceptor);
                put(25, japiTokenInterceptor);
            }
        };
    }
}
